import { isUndefined, isType } from '../utils'

class Event{
  _events = {}

  init(){
    this._events = {}
  }

  on( evname , params , no){
    this._events = this._events || {}
    this._events[evname] = this._events[evname] || []
    if(!params) return
    const No = isType(no, 'Undefined') ? 0 : no
    const v = {
      handle: isType(params, 'Function') ? params : params.handle,
      scope: !isUndefined(params.scope) ? params.scope : this,
      args: !isUndefined(params.args) ? params.args : [],
      once: !isUndefined(params.once) ? params.once : false,
      pre: !isUndefined(params.pre) ? params.pre : true,
      no: No
    }
    if(no === 'first'){
      this._events[evname].splice(0,0, v)
    }else if(no === 'last'){
      this._events[evname].push(v)
    } else {
      let i=0;
      for(;i<this._events.length; i++){
        let vno = this._events[i].no
        if(vno==='first') continue;
        if(vno==='last') break;
        if(vno>no) break;
      }
      this._events[evname].splice(i, 0, v)
    }
    
    return this
  }

  once (evname, params ){
    const p = isType(params, 'Function') ? {
      handle: params,
      once: true
    } : Object.assign(params, {once: true})
    return this.on(evname, p)
  }

  trigger (evname) {
    const args = Array.prototype.slice.call(arguments, 1)
    const results = []
    if (this._events[evname] && this._events[evname].length>0 ){
      this._events[evname] = this._events[evname].reduce( (t, v, i)=>{
        if(v.handle){
          const scope = v.scope
          const pre = isType(v.pre, 'Function') ? pre.apply(scope, args) : v.pre
          if(pre){
            results.push( v.handle.apply(scope, args) )
            if( !v.once ){
              t = [...t, v]
            }
          }
        }
        return t
      }, [])
    }
    results.get = function(index){
      return results[index]
    }
    return results.length>0 ? results : null
  }

  hasEvent( etag ){
    return (this._events[ etag ] && this._events[ etag ].length>0)
  }

  emit( etag ){
    const args = Array.prototype.slice.call(arguments)
    if( this.hasEvent(etag) ){
      this.trigger(...args)
    }else if( this._parent ){
      this._parent.emit && this._parent.emit(...args)
    }else{
      console.warn('The event cannt found:' + etag )
    }
  }

  emitAll( etag ){
    const args = Array.prototype.slice.call(arguments)
    if( this.hasEvent(etag) ){
      this.trigger(...args)
      console.log(`Trigger Event ${etag} in ${this._nodeTag}`)
    }

    if( this._parent ){
      this._parent.emit && this._parent.emit(...args)
    }
  }
}

export default Event